package com.hls.mongo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.hls.mongo.core.ConfigReader;
import com.hls.mongo.core.GsonHelper;

public class Mongo {
    public static String dbfilename;
    
    /**
     * initialize the database store
     * @throws IOException
     */
    public Mongo() throws IOException
    {
       
        String dbStore = "";
        
        URL url = Class.class.getResource("/mongo.xml");
        Map<String,String> map = null;
        if(url!=null)
        {
            map = ConfigReader.configure(url.getPath().substring(1));
        }
        else
        {
            System.out.println("no configuration file found!");
        }
        
        if(map != null && map.get("dbstore") != null)
        {
            dbStore = map.get("dbstore");
        }
        
        if(dbStore.length() == 0)
        {
            dbStore =  Class.class.getResource("/").getPath().substring(1);
        }
        
        File dbfile = new File(dbStore+"/mongostore.xml");
        if(!dbfile.exists())
        {
            File fileParent = dbfile.getParentFile();  
            if(!fileParent.exists()){  
                fileParent.mkdirs();  
            }
            
            FileOutputStream dbStoreFile = new FileOutputStream(dbfile.getPath());
            Document document = new Document();
            Element root = new Element("mongo");
            Element database = new Element("database");
            database.setAttribute("name", "test");
            
            root.addContent(database);
            document.setRootElement(root);
            XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
            out.output(document, dbStoreFile);
           
            System.out.println("db store file created!");
        }
        
        dbfilename = dbfile.getPath();
        System.out.println("dbfile name:"+dbfilename);
    }

    /**
     * create database
     * @param name
     */
    public void createDatabase(String name)
    {
        SAXBuilder builder = new SAXBuilder();
        Document document;
        try {
            FileInputStream file = new FileInputStream(this.dbfilename);
            document = builder.build(file);
            
            Element root = document.getRootElement();
            Element child = new Element("database");
            child.setAttribute("name",name);
            root.addContent(child);
            XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
            out.output(document, new FileOutputStream(this.dbfilename));
            System.out.println("create database:"+name);
        }
        catch(Exception e)
        {
            e.printStackTrace();
            System.out.println("exception occured when createing the database.");
        }
    }
    
    /**
     * 
     * @param databaseName
     * @param entity
     * @return if return null then
     */
    public String insert(String databaseName, Object entity)
    {
        String uniqueId = null;
        SAXBuilder builder = new SAXBuilder();
        Document document;
        try {
            FileInputStream file = new FileInputStream(this.dbfilename);
            document = builder.build(file);
            Element root = document.getRootElement();
            List<Element> child = root.getChildren();
            String tempUniqueId = UUID.randomUUID().toString().replace("-", "");
            for(Element item : child)
            {
               if(item.getAttribute("name").getValue().equals(databaseName))
               {
                   Element data = new Element("data");
                   String json = GsonHelper.entityToJSONString(entity);
                   //cast to json object and add id property
                   JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
                   jsonObject.addProperty("_id", tempUniqueId);
                   
                   data.addContent(jsonObject.toString());
                   item.addContent(data);
               }
            }
            XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
            out.output(document, new FileOutputStream(this.dbfilename));
            System.out.println("insert to database:"+databaseName);
            uniqueId = tempUniqueId;
        }
        catch(Exception e)
        {
            e.printStackTrace();
            System.out.println("exception occured when inserting the data to the database.");
        }
        return uniqueId;
    }
    
    /**
     * 
     * @param databaseName
     * @param entity
     * @return if return null then
     */
    public boolean update(String databaseName,String uuid, Object entity)
    {
        boolean ret = false;
        
        SAXBuilder builder = new SAXBuilder();
        Document document;
        try {
            FileInputStream file = new FileInputStream(this.dbfilename);
            document = builder.build(file);
            Element root = document.getRootElement();
            List<Element> child = root.getChildren();
            for(Element item : child)
            {
               if(item.getAttribute("name").getValue().equals(databaseName))
               {
                   List<Element> subChild = item.getChildren();
                   for(Element subItem : subChild)
                   {
                       JsonObject jsonObject = new JsonParser().parse(subItem.getValue()).getAsJsonObject();
                       if(jsonObject.get("_id")!=null && jsonObject.get("_id").getAsString().equals(uuid))
                       {
                           subItem.removeContent();
                           String json = GsonHelper.entityToJSONString(entity);
                           //cast to json object and add id property
                           JsonObject subJsonObject = new JsonParser().parse(json).getAsJsonObject();
                           subJsonObject.addProperty("id", uuid);
                           subItem.addContent(subJsonObject.toString());
                       }
                   }
               }
            }
            XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
            out.output(document, new FileOutputStream(this.dbfilename));
            System.out.println("upate database:"+databaseName);
        }
        catch(Exception e)
        {
            e.printStackTrace();
            System.out.println("exception occured when updating the data to the database.");
        }
        
        return ret;
    }
    
    /**
     * get database record
     * @param databaseName
     * @return
     */
    public List<String> getList(String databaseName)
    {
        List<String> retList = new ArrayList<String>();
        
        SAXBuilder builder = new SAXBuilder();
        Document document;
        try {
            FileInputStream file = new FileInputStream(this.dbfilename);
            document = builder.build(file);
            Element root = document.getRootElement();
            List<Element> child = root.getChildren();
            for(Element item : child)
            {
               if(item.getAttribute("name").getValue().equals(databaseName))
               {
                   List<Element> subChild = item.getChildren();
                   for(Element subItem : subChild)
                   {
                       retList.add(subItem.getValue());
                   }
               }
            }
            XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
            out.output(document, new FileOutputStream(this.dbfilename));
        }
        catch(Exception e)
        {
            e.printStackTrace();
            System.out.println("exception occured when ge the all data form the database.");
        }
        return retList;
    }
    
    /**
     * 
     * @param databaseName
     * @param entity
     * @return if return null then
     */
    public boolean delete(String databaseName,String uuid)
    {
        boolean ret = false;
        
        SAXBuilder builder = new SAXBuilder();
        Document document;
        try {
            FileInputStream file = new FileInputStream(this.dbfilename);
            document = builder.build(file);
            Element root = document.getRootElement();
            List<Element> child = root.getChildren();
            for(Element item : child)
            {
               if(item.getAttribute("name").getValue().equals(databaseName))
               {
                   List<Element> subChild = item.getChildren();
                   for(Element subItem : subChild)
                   {
                       JsonObject jsonObject = new JsonParser().parse(subItem.getValue()).getAsJsonObject();
                       if(jsonObject.get("_id")!=null && jsonObject.get("_id").getAsString().equals(uuid))
                       {
                           item.removeContent(subItem);
                           ret = true;
                           break;
                       }
                   }
               }
            }
            XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
            out.output(document, new FileOutputStream(this.dbfilename));
        }
        catch(Exception e)
        {
            e.printStackTrace();
            System.out.println("exception occured when deleting the data to the database.");
        }
        
        return ret;
    }
    
    /**
     * delete database
     * @param databaseName
     * @return
     */
    public boolean dropDatabase(String databaseName)
    {
        boolean ret = false;
        
        SAXBuilder builder = new SAXBuilder();
        Document document;
        try {
            FileInputStream file = new FileInputStream(this.dbfilename);
            document = builder.build(file);
            Element root = document.getRootElement();
            List<Element> child = root.getChildren();
            for(Element item : child)
            {
               if(item.getAttribute("name").getValue().equals(databaseName))
               {
                   child.remove(item);
                   ret = true;
                   break;
               }
            }
            XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
            out.output(document, new FileOutputStream(this.dbfilename));
        }
        catch(Exception e)
        {
            e.printStackTrace();
            System.out.println("exception occured when droping the database.");
        }
        
        return ret;
    }
}
